package com.zzl.bonds.ticket.service.impl;

import cfca.trustsign.common.vo.cs.SignInfoVO;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzl.bonds.ticket.constant.*;
import com.zzl.bonds.ticket.constant.status.*;
import com.zzl.bonds.ticket.constant.type.*;
import com.zzl.bonds.ticket.dao.TicketFinanceDao;
import com.zzl.bonds.ticket.dto.ApUserShowInfo;
import com.zzl.bonds.ticket.dto.KeyValue;
import com.zzl.bonds.ticket.dto.TicketDataDto;
import com.zzl.bonds.ticket.dto.TicketFinanceDataTypeDto;
import com.zzl.bonds.ticket.dto.common.MsgInfoDto;
import com.zzl.bonds.ticket.dto.feign.*;
import com.zzl.bonds.ticket.dto.finance.*;
import com.zzl.bonds.ticket.dto.order.OrderAddDto;
import com.zzl.bonds.ticket.dto.ticketopen.CheckSubmit;
import com.zzl.bonds.ticket.entity.*;
import com.zzl.bonds.ticket.entity.feign.ContractEntity;
import com.zzl.bonds.ticket.exception.SysExceptionFactory;
import com.zzl.bonds.ticket.feign.AnXinSignFeign;
import com.zzl.bonds.ticket.feign.BaseDataFeign;
import com.zzl.bonds.ticket.feign.ContractFeign;
import com.zzl.bonds.ticket.feign.OrderFeign;
import com.zzl.bonds.ticket.manager.TicketFlowChartManager;
import com.zzl.bonds.ticket.service.*;
import com.zzl.bonds.ticket.service.common.MailMessageService;
import com.zzl.bonds.ticket.service.common.TicketCommonService;
import com.zzl.bonds.ticket.service.common.TicketFinanceHandService;
import com.zzl.bonds.ticket.untils.*;
import com.zzl.general.common.constant.Constant;
import com.zzl.general.common.exception.SysException;
import com.zzl.general.common.serurity.entity.User;
import com.zzl.general.common.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zzl.bonds.ticket.constant.StringConstant.TICKET_STATUS;
import static com.zzl.bonds.ticket.constant.status.ApproveResultStatusEnum.APPROVE_STATUS_NO;
import static com.zzl.bonds.ticket.constant.status.TicketStatusEnum.*;
import static com.zzl.bonds.ticket.exception.SysExceptionEnum.*;
import static com.zzl.bonds.ticket.untils.DateUtils.YYYY_MM_DD_HH_MM_SS;

/**
 * 融资申请单
 *
 * @author wztsl
 * @date 2022-02-24 13:53:42
 */
@Service("ticketFinanceService")
public class TicketFinanceServiceImpl extends ServiceImpl<TicketFinanceDao, TicketFinanceEntity> implements TicketFinanceService {
    @Autowired
    private TicketService ticketService;
    @Autowired
    private BaseDataFeign baseDataFeign;
    @Autowired
    @SuppressWarnings("all")
    private RedisTemplate redisTemplate;
    @Autowired
    private TicketDataService ticketDataService;
    @Autowired
    private TicketFlowChartManager ticketFlowChartManager;

    @Autowired
    private TicketOperateLogService ticketOperateLogService;
    @Autowired
    private TicketCommonService ticketCommonService;
    @Autowired
    private TicketFinanceHandService ticketFinanceHandService;
    @Autowired
    private MailMessageService mailMessageService;
    @Autowired
    private ContractemplateService contractemplateService;
    @Autowired
    private BusinessContractService businessContractService;
    @Autowired
    private OrderFeign orderFeign;
    @SuppressWarnings("all")
    @Autowired
    private SupplierCreditService supplierCreditService;
    @Autowired
    private ContractFeign contractFeign;

    @Autowired
    private AnXinSignFeign anXinSignFeign;
    @Autowired
    private TicketProcessService ticketProcessService;
    @Autowired
    private TicketFinanceDataService ticketFinanceDataService;
    @Autowired
    private TicketFlowChartService ticketFlowChartService;

    /**
     * 分页查询
     *
     * @param params 查询参数
     * @return 分页数据
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params, User user) throws SysException {
        IPage<TicketFinanceListDto> page = setTicketFinanceListParams(params, user);
        this.setHandStatusParams(params);
        IPage<TicketFinanceListDto> openPage = this.baseMapper.queryPage(page, params);
        List<TicketFinanceListDto> pageRecords = openPage.getRecords();
        if (!CollectionUtils.isEmpty(pageRecords)) {
            ticketFinanceHandService.setFinanceTicketHandleSituation(pageRecords);
            ticketFinanceHandService.setFinanceTicketOperates(pageRecords);
        }
        return new PageUtils(openPage);


    }

    /**
     * 新增
     * 1、校验：凭证是否存在；转让金额大于等于融资本金；转让金额小于等于凭证金额；预兑付
     * 2、金融机构选择，查询金融机构下面的金融产品，计算利息
     * 3、拆单：融资凭证需要根据母单信息进行拆，将我的票据拆分成多个凭证
     * 4、设置对象值：金融产品数值计算、开户行、发票信息、凭证信息、融资企业 id、融资方名称financeEnterpriseName 、
     * fileIds凭证资料id、凭证资料地址filePath
     * 融资上链地址financeBillAddress
     * 融资编号financeBillNo
     * 票据状态ticketStatus、审批状态approveStatus
     * 融资成本financingCost
     * 额度编号
     * 5、融资授信扣减
     *
     * @param ticketFinanceAddDto 新增实体
     * @param user                当前登录用户
     * @throws SysException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveTicketFinance(TicketFinanceAddDto ticketFinanceAddDto, User user) throws SysException {
        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        TicketEntity ticket = ticketService.getById(ticketFinanceAddDto.getTicketId());
        if (ticket == null) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_BY_ID_ERROR);
        }
        //1 校验
        this.checkFinanceTicket(ticketFinanceAddDto, ticket, user);
        BeanUtils.copyProperties(ticketFinanceAddDto, ticketFinanceEntity);
        //2 金融产品参数计算
//        this.saveTicketFinanceProduct(ticketFinanceAddDto, ticketFinanceEntity);
        // 融资地址设置
        this.saveTicketFinanceThird(ticketFinanceEntity);
        //3 拆单
        this.saveTicketFinanceSplit(ticket, ticketFinanceAddDto, ticketFinanceEntity, user);
        //4 设置实体类
        this.saveTicketFinanceSetting(ticket, ticketFinanceAddDto, ticketFinanceEntity, user);
        //5 处理发票和凭证文件
        this.saveTicketData(ticketFinanceAddDto, ticketFinanceEntity, user);
        // 保存融资申请单
        if (!this.save(ticketFinanceEntity)) {
            throw new SysException("A00001", "保存失败！");
        }
        // 融资补充资料保存
        this.setFinanceDataType(ticketFinanceAddDto.getFinanceDataDtoList(), ticketFinanceEntity.getId(), user);
        //6、融资授信扣减,设置融资编号credit_no
        this.setTicketFinanceFrozenCredit(ticketFinanceAddDto, ticketFinanceEntity, user);
        //7 操作日志
        ticketOperateLogService.saveTicketLog(ticketFinanceEntity, user);
        //8 融资提交申请后，给复核人发消息
        //生成订单数据 todo
//        this.saveOrderDetail(ticketFinanceEntity);
        //8、拉起开单复核合同协议
        this.setBusinessProtocol(ticketFinanceEntity.getId(), ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());
        //9、拉起审批流程
        //拉起融资复核流程，并给复核人发送消息
        MsgInfoDto msgInfoDto = mailMessageService.setTicketFinanceMsg(ticketFinanceEntity, user);
        ticketProcessService.saveTicketProcess(ticketFinanceEntity.getFinanceAmount()
                , ticketFinanceEntity.getId(), JSON.toJSONString(msgInfoDto), ApproveTypeEnum.FINANCE, user
                , null
                , TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode().toString());

        //10 流程轨迹保存
        this.saveFinacneFlowChart(ticketFinanceEntity, user);
        return ticketFinanceEntity.getId();
    }

    /**
     * 添加融资轨迹
     *
     * @param ticketFinanceEntity 融资
     * @param user                用户
     * @throws SysException 异常
     */
    private void saveFinacneFlowChart(TicketFinanceEntity ticketFinanceEntity, User user) throws SysException {
        TicketFlowChartEntity parentEntity = ticketFlowChartService.getOneByTicketId(ticketFinanceEntity.getParentTicketId());
        //修改父票颜色为蓝色
        parentEntity.setTicketStatus(FlowChartColourEnum.BLUE.getCode());
        ticketFlowChartService.updateById(parentEntity);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtils.DF_YYYY_MM_DD);
        TicketFlowChartEntity ticketFlowChartEntity = new TicketFlowChartEntity();
        ticketFlowChartEntity.setTitle("凭证编号：" + ticketFinanceEntity.getTicketNo());
        ticketFlowChartEntity.setSignEnterpriseName("融资金融机构：" + ticketFinanceEntity.getInstinctyName());
        ticketFlowChartEntity.setMoneyAmountFirst("凭证金额：" + StrUtils.simgleFormat(ticketFinanceEntity.getFinanceAmount()) + " 元");
        ticketFlowChartEntity.setFirstTime("融资日期：" + simpleDateFormat.format(ticketFinanceEntity.getCreateTime()));
        ticketFlowChartEntity.setUppercaseAmount("人民币" + NumberToCN.number2CNMontrayUnit(BigDecimal.valueOf(ticketFinanceEntity.getFinanceAmount())));
        ticketFlowChartEntity.setApplyId(ticketFinanceEntity.getId());
        ticketFlowChartEntity.setParentId(parentEntity.getId());
        ticketFlowChartEntity.setTicketId(ticketFinanceEntity.getTicketId());
        ticketFlowChartEntity.setType(FlowChartTypeEnum.FINANCE.getCode());
        ticketFlowChartEntity.setTicketOpenId(parentEntity.getTicketOpenId());
        ticketFlowChartEntity.setTicketStatus(FlowChartColourEnum.YELLOW.getCode());
        if (StringUtils.isNotBlank(ticketFinanceEntity.getRetentionTicketId())) {
            TicketEntity ticket = ticketService.getById(ticketFinanceEntity.getRetentionTicketId());
            TicketFlowChartEntity retentionFlowChartEntity = new TicketFlowChartEntity();
            retentionFlowChartEntity.setTitle("凭证编号：" + ticketFinanceEntity.getRetentionTicketNo());
            retentionFlowChartEntity.setSignEnterpriseName("签收企业：" + ticket.getEnterpriseName());
            retentionFlowChartEntity.setFirstTime("签收日期：" + simpleDateFormat.format(ticket.getCreateTime()));
            retentionFlowChartEntity.setMoneyAmountFirst("凭证金额：" + StrUtils.simgleFormat(ticket.getTicketAllAmount()) + " 元");
            retentionFlowChartEntity.setUppercaseAmount("人民币" + NumberToCN.number2CNMontrayUnit(BigDecimal.valueOf(ticket.getTicketAllAmount())));
            retentionFlowChartEntity.setApplyId(ticketFinanceEntity.getId());
            retentionFlowChartEntity.setParentId(parentEntity.getId());
            retentionFlowChartEntity.setTicketId(ticketFinanceEntity.getRetentionTicketId());
            retentionFlowChartEntity.setType(FlowChartTypeEnum.FINANCE.getCode());
            retentionFlowChartEntity.setTicketOpenId(ticket.getTicketOpenId());
            retentionFlowChartEntity.setTicketStatus(FlowChartColourEnum.YELLOW.getCode());
            ticketFlowChartService.saveTicketFlowChartEntity(Arrays.asList(ticketFlowChartEntity, retentionFlowChartEntity), user);
        } else {
            ticketFlowChartService.saveTicketFlowChartEntity(Collections.singletonList(ticketFlowChartEntity), user);
        }

    }

    /**
     * 融资补充资料保存
     *
     * @param financeDataDtoList 融资资料
     * @param id                 融资申请id
     * @param user               用户
     */
    private void setFinanceDataType(List<TicketFinanceDataTypeDto> financeDataDtoList, String id, User user) {
        if (CollectionUtils.isEmpty(financeDataDtoList)) {
            return;
        }
        ticketFinanceDataService.saveTicketBatchfinanceData(financeDataDtoList, id, user);
    }

    /**
     * 融资授信冻结扣减,设置融资编号credit_no
     *
     * @param ticketFinanceAddDto 融资申请
     * @param ticketFinanceEntity 融资实体
     * @param user                用户
     */
    private void setTicketFinanceFrozenCredit(TicketFinanceAddDto ticketFinanceAddDto, TicketFinanceEntity ticketFinanceEntity, User user) throws SysException {
        SupplierCreditEntity supplierCreditEntity = supplierCreditService.frozenFinanceSupplierCredit(ticketFinanceAddDto, user);
        ticketFinanceEntity.setCreditNo(supplierCreditEntity.getCreditNo());
    }

    /**
     * 生成订单数据
     *
     * @param ticketFinanceEntity 融资申请数据
     */
    private void saveOrderDetail(TicketFinanceEntity ticketFinanceEntity) throws SysException {
        OrderAddDto orderAddDto = new OrderAddDto();
        orderAddDto.setTicketNo(ticketFinanceEntity.getTicketNo());
        orderAddDto.setServiceChage(ticketFinanceEntity.getServiceChage());
        orderAddDto.setEstimatedFinancingInterest(ticketFinanceEntity.getAnnualizedInterest());
        orderAddDto.setFinanceInfo(JSON.toJSONString(ticketFinanceEntity));
        orderAddDto.setSellAmount(ticketFinanceEntity.getFinanceAmount());
        orderAddDto.setInstinctyId(ticketFinanceEntity.getInstinctyId());
        orderAddDto.setInstinctyName(ticketFinanceEntity.getInstinctyName());
        orderAddDto.setFinanceEnterpriseId(ticketFinanceEntity.getEnterpriseId());
        orderAddDto.setFinanceEnterpriseName(ticketFinanceEntity.getFinanceEnterpriseName());
        Result result = orderFeign.save(orderAddDto);
        if (null == result) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_ORDER_SAVE_ERROR);
        }
        if (ResultCode.SUCCESS.getCode() != result.getCode()) {
            throw new SysException(result.getMsg());
        }
    }

    /**
     * 发送消息类消息，给指定用户集合
     *
     * @param userIdList 消息接收用户集合
     * @param msgContent 消息内容
     * @param user       登录用户
     * @throws SysException 业务异常
     */
    private void sendFinanceOrdinaryMsg(TicketFinanceEntity financeEntity, String msgContent, List<Integer> userIdList, User user) throws SysException {
        //消息处理
        //    String msg = msgContent.
        //           replace(FINANCIAL_INSTITUTION_KEY, financeEntity.getInstinctyName()).
        //           replace(TICKET_AMOUNT_KEY, NumberUtil.numberFormatString(financeEntity.getTicketAmount()));
        //    sendMsgService.sendMsgToMq(MsgCategoryEnum.MSG_CATEGORY_ORDINARY.getCode(), msg, userIdList, user, new ArrayList<>());
    }

    /**
     * 3、拆单：
     * 融资凭证需要根据母单信息进行拆，将我的票据拆分成多个凭证
     * 根据金额判断拆成一张还是两张
     * 变更母单冻结金额和可用金额、凭证状态
     * 更新母单
     * 拼装新的子单数据，状态、金额
     * 新增子单
     *
     * @param ticket              我的凭证
     * @param ticketFinanceAddDto 融资申请
     * @param ticketFinanceEntity 融资实体
     * @param user                登录用户
     */
    private void saveTicketFinanceSplit(TicketEntity ticket, TicketFinanceAddDto ticketFinanceAddDto,
                                        TicketFinanceEntity ticketFinanceEntity, User user) throws SysException {
        //设置融单id，
        ticketFinanceEntity.setId(UuidUtils.UUID());
        //1 我的票据拆分
        List<TicketEntity> ticketEntityList = new ArrayList<>();
        TicketEntity newTicket1 = new TicketEntity();
        TicketEntity newTicket2 = new TicketEntity();
        TicketEntity parentTicket = new TicketEntity();
        //开发会议确定逻辑：融单提交，母单状态已失效，融单状态融单中，子单 状态正常持有，冻结状态为冻结
        //原始票据修改：母单状态变更，已失效
        parentTicket.setFinanceFrozenAmount(ticketFinanceAddDto.getFinanceAmount());
        parentTicket.setId(ticket.getId());
        parentTicket.setTicketStatus(TicketStatusEnum.INVALID.getCode());
        parentTicket.setInvalidReason(InvalidReasonEnum.TICKET_FINANCE_SUCCESS.getValue());
        parentTicket.setUpdaterId(user.getId());
        ticketEntityList.add(parentTicket);
        //转让金额 等于我的凭证金额
        BeanUtils.copyProperties(ticket, newTicket1);
        newTicket1.setId(UuidUtils.UUID());
        newTicket1.setParentId(ticket.getId());
        newTicket1.setEnterpriseId(user.getEnterpriseId());
        newTicket1.setOrgId(newTicket1.getOrgId());
        newTicket1.setCreatorId(user.getId());
        newTicket1.setUpdaterId(user.getId());
        newTicket1.setTicketNo(TicketNoUtils.getTicketNo(redisTemplate));
        newTicket1.setTicketAllAmount(ticketFinanceAddDto.getFinanceAmount());
        newTicket1.setTicketAvailableAmount(ticketFinanceAddDto.getFinanceAmount());
        newTicket1.setTicketSurplusAmount(ticketFinanceAddDto.getFinanceAmount());
        newTicket1.setFinanceAmount(0.0);
        newTicket1.setTransferAmount(0.0D);
        newTicket1.setTicketStatus(MyTicketStatusEnum.FINANCE_UNDER_REVIEW.getCode());
        newTicket1.setParentBusinessId(ticketFinanceEntity.getId());
        newTicket1.setTicketTypeSource(TicketTypeSourceEnum.OPEN_FINANCE.getCode());
        newTicket1.setChainAddress(this.getTicketChainAddress());
        ticketEntityList.add(newTicket1);
        //转让金额< 我的凭证金额
        if (ticket.getTicketAllAmount() > ticketFinanceAddDto.getFinanceAmount()) {
            BeanUtils.copyProperties(newTicket1, newTicket2);
            newTicket2.setId(UuidUtils.UUID());
            newTicket2.setTicketNo(TicketNoUtils.getTicketNo(redisTemplate));
            newTicket2.setTicketAllAmount(ticket.getTicketAllAmount() - ticketFinanceAddDto.getFinanceAmount());
            newTicket2.setTicketAvailableAmount(ticket.getTicketAllAmount() - ticketFinanceAddDto.getFinanceAmount());
            newTicket2.setTicketSurplusAmount(ticket.getTicketAllAmount() - ticketFinanceAddDto.getFinanceAmount());
            newTicket2.setFrozenState(FrozenStatusEnum.FROZEN_STATUS_YES.getCode());
            newTicket2.setChainAddress(this.getTicketChainAddress());
            if (TicketTypeSourceEnum.OPEN_IN_LIST.contains(ticket.getTicketTypeSource())) {
                newTicket2.setTicketTypeSource(TicketTypeSourceEnum.OPEN_FINANCE_KEEP.getCode());
            } else if (TicketTypeSourceEnum.TRANSFER_IN_LIST.contains(ticket.getTicketTypeSource())) {
                newTicket2.setTicketTypeSource(TicketTypeSourceEnum.TRANSFER_FINANCE_KEEP.getCode());
            } else if (TicketTypeSourceEnum.FINANCE_IN_LIST.contains(ticket.getTicketTypeSource())) {
                newTicket2.setTicketTypeSource(TicketTypeSourceEnum.FINANCE_KEEP.getCode());
            } else {
                throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_SOURCE_ERROR);

            }

            ticketEntityList.add(newTicket2);
            ticketFinanceEntity.setRetentionTicketId(newTicket2.getId());
            ticketFinanceEntity.setRetentionTicketNo(newTicket2.getTicketNo());
        }

        if (!ticketService.saveOrUpdateBatch(ticketEntityList)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_SAVE_ERROR);
        }

        ticketFinanceEntity.setTicketNo(newTicket1.getTicketNo());
        ticketFinanceEntity.setTicketId(newTicket1.getId());
        ticketFinanceEntity.setParentTicketId(ticket.getId());
        ticketFinanceEntity.setParentTicketNo(ticket.getTicketNo());
        //处理母单绑定的资料信息
        List<TicketDataEntity> byTicketId = ticketDataService.getByTicketId(ticket.getId(), TicketActionTypeEnum.TICKET_TYPE_TICKET.getCode());
        if (!CollectionUtils.isEmpty(byTicketId)) {
            ticketEntityList.forEach(y -> {
                byTicketId.forEach(x -> {
                    x.setId(UuidUtils.UUID());
                    x.setTicketActionId(y.getId());
                    x.setTicketActionType(TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode());
                });
                ticketDataService.saveBatch(byTicketId);
            });

        }
    }

    /**
     * 设置上链地址
     *
     * @return 上链地址
     */
    private String getTicketChainAddress() {
        return "上链地址";
    }

    /**
     * 2、设置对象值：
     * 金融产品数值计算、开户行、发票信息、凭证信息、融资企业 id、融资方名称financeEnterpriseName 、
     * fileIds凭证资料id、凭证资料地址filePath
     * 融资上链地址financeBillAddress
     * 融资编号financeBillNo
     * 票据状态ticketStatus、审批状态approveStatus
     * 融资成本financingCost
     * <p>
     * 新增
     * 处前端传值以外还要处理5组值：
     * 3、票据对象获取
     * ticket
     * 票据编号：ticketNo;
     * 5、主动设置
     * setting
     * 融资状态，1：待融资（平台审核中），2：待放款，3：已放款：financeStatus;
     * 审核状态，1：审核中，2：驳回，3：审核通过：approveStatus;
     * 融资方式, 0:无方式，,1:买断式，2：回购式：financeType;
     * 申请企业id：enterpriseId;
     * 部门id：orgId;
     * 创建时间：createTime;
     * 修改时间：updateTime;
     * 创建人：creatorId;
     * 1 表示删除，0 表示未删除：isDeleted;
     * 放款金额：loanAmount;
     * 融资开户行行号：finance_deposit_bank_no
     * 融资对公账户：finance_deposit_bank
     * 融资银行账号id：finance_bank_id
     * 6、处理附件
     *
     * @param ticket 我的票据对象
     * @param entity 票据融资对象
     * @param user   当前登录用户
     */
    private void saveTicketFinanceSetting(TicketEntity ticket, TicketFinanceAddDto ticketFinanceAddDto,
                                          TicketFinanceEntity entity, User user) {
        //                * 金融产品数值计算、开户行、发票信息、凭证信息、融资方名称financeEnterpriseName 、
        entity.setCashTime(ticket.getCashTime());
        entity.setTicketAmount(ticketFinanceAddDto.getFinanceAmount());
        entity.setOpenEnterpriseId(ticket.getOpenEnterpriseId());
        entity.setOpenEnterpriseName(ticket.getOpenEnterpriseName());
        entity.setTicketOriginId(ticket.getTicketOriginId());
        entity.setEnterpriseId(ticket.getEnterpriseId());
        entity.setFinanceEnterpriseName(ticket.getEnterpriseName());
        entity.setFinanceBillNo(TicketNoUtils.getTicketFinanceNo(redisTemplate));
        entity.setTicketStatus(TicketStatusEnum.FINANCE_PENDING_REVIEW.getCode());
        entity.setEnterpriseId(user.getEnterpriseId());
        entity.setOrgId(user.getOrgId());
        entity.setCreatorId(user.getId());
        entity.setUpdaterId(user.getId());
        entity.setLoanAmount(0.0);
        entity.setFullNameOpeningBank(ticketFinanceAddDto.getFullNameOpeningBank());
        entity.setFinanceDepositBank(ticketFinanceAddDto.getFinanceDepositBank());
        entity.setFinanceBankId(ticketFinanceAddDto.getFinanceBankId());
        entity.setTransferEnterpriseId(ticket.getTransferEnterpriseId());
        entity.setTransferEnterpriseName(ticket.getTransferEnterpriseName());
        entity.setFinanceDepositBankName(ticketFinanceAddDto.getAccountOpeningOutlet());
        //预计融资天数
        String days = ticketCommonService.calculateSurplusDays(entity.getExpireTime()
                , TicketStatusEnum.WAITING_PAYMENT.getCode());
        String financeDays = days.substring(2, days.length() - 2);
        entity.setFinanceDays(Integer.parseInt(financeDays));
        entity.setEstimateDisbursementDate(ticketFinanceAddDto.getEstimateDisbursementDate());
    }

    /**
     * 处理发票和凭证文件
     *
     * @param ticketFinanceAddDto 融资申请信息
     * @param entity              融资申请单实体
     * @param user                登录用户
     */
    private void saveTicketData(TicketFinanceAddDto ticketFinanceAddDto,
                                TicketFinanceEntity entity, User user) throws SysException {
        //fileIds凭证资料id、凭证资料地址filePath
        // 保存开立相关的资料
        List<TicketDataDto> allFileList = new ArrayList<>();
        //融资发票信息
        List<TicketDataDto> invoiceList = ticketFinanceAddDto.getInvoiceList();
        //融资凭证资料
        List<TicketDataDto> fileList = ticketFinanceAddDto.getProofList();
        if (!CollectionUtils.isEmpty(invoiceList)) {
            allFileList.addAll(invoiceList);
        }
        if (!CollectionUtils.isEmpty(fileList)) {
            allFileList.addAll(fileList);
        }
        if (!CollectionUtils.isEmpty(allFileList)) {
            allFileList.forEach(x -> {
                x.setTicketActionType(TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode());
                x.setTicketActionId(entity.getId());
            });
            //保存发票信息，包括发票ocr识别
            ticketDataService.saveTicketData(allFileList, user);
        }
    }

    /**
     * 新增
     * 处前端传值以外还要处理5组值：
     * 4、区块链服务获取
     * third
     * 融资上链地址：financeBillAddress;
     *
     * @param entity 票据融资对象
     */
    @SuppressWarnings("unused")
    private void saveTicketFinanceThird(TicketFinanceEntity entity) {
        entity.setFinanceBillAddress("融资上链地址");
    }

    /**
     * 新增
     * 处前端传值以外还要处理5组值：
     * 2、工具类获取
     * utils
     * 融资编号：financeBillNo;
     *
     * @param entity 票据融资对象
     */
    private void saveTicketFinanceUtils(TicketFinanceEntity entity) {
        entity.setFinanceBillNo(TicketNoUtils.getTicketFinanceNo(redisTemplate));
    }

    /**
     * 1、校验：
     * 凭证是否存在；
     * 银行账号是否存在
     * 转让金额不小于融资本金；转让金额小于等于凭证金额；
     * 预兑付
     *
     * @param ticketFinanceAddDto 融资申请信息
     * @throws SysException 业务异常
     */
    private void checkFinanceTicket(TicketFinanceAddDto ticketFinanceAddDto, TicketEntity ticket, User user) throws SysException {
        //金额校验
        if (ticketFinanceAddDto.getFinanceAmount() > ticketFinanceAddDto.getTicketAmount()) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_CHECK_AMOUNT_ERROR);
        }
        if (ticketFinanceAddDto.getFinanceAmount() > ticket.getTicketAllAmount()) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_CHECK_TICKET_AMOUNT_ERROR);
        }
        //预兑付校验
        if (AdvancePaymentStatusEnum.COULD.getCode().equals(ticket.getAdvancePaymentStatus())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_CHECK_ADVANCE_PAYMENT_ERROR);
        }
        if (!user.getEnterpriseId().equals(ticket.getEnterpriseId())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_OWNER_IS_CHANGED_ERROR);
        }
        //凭证状态
        if (!TicketStatusEnum.NORMAL_HOLDING.getCode().equals(ticket.getTicketStatus())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_CHECK_TICKET_STATUS_ERROR);
        }
        //  校验银行账号是否正确，调用b服务接口，根据账号id查询账户信息
        this.checkFinanceBank(ticketFinanceAddDto);

    }

    /**
     * 校验银行账号是否正确，调用b服务接口，根据账号id查询账户信息
     *
     * @param ticketFinanceAddDto 融资申请信息
     * @return 是否校验通过  true 通过   false 不通过
     */
    private boolean checkFinanceBank(TicketFinanceAddDto ticketFinanceAddDto) throws SysException {
        BankAccountEntity bankAccountFeign = baseDataFeign.getBankAccountFeign(ticketFinanceAddDto.getFinanceBankId());
        boolean bankFlag = false;
        if (!ObjectUtils.isEmpty(bankAccountFeign)) {
            if (!ticketFinanceAddDto.getFinanceDepositBank().equals(bankAccountFeign.getCorporateAccount()) ||
                    !ticketFinanceAddDto.getAccountOpeningOutlet().equals(bankAccountFeign.getAccountOpeningOutlet())) {
                throw SysExceptionFactory.createSysException(TICKET_FINANCE_CHECK_BANK_ERROR);
            }
            bankFlag = true;

        }
        return bankFlag;
    }

    /**
     * 新增
     * 处前端传值以外还要处理5组值：
     * 1、金融产品获取
     * product
     * 预估放款金额：estimateLoanAmount;
     * 放款比例：loanProprotion;
     * 年化利率：annualizedInterestRate;
     * 服务费：serviceChage;
     * 预计放款日期：estimateDisbursementDate;
     *
     * @param ticketFinanceAddDto 新增实体
     * @param entity              票据融资对象
     * @throws SysException 业务异常
     */
    private void saveTicketFinanceProduct(TicketFinanceAddDto ticketFinanceAddDto, TicketFinanceEntity entity) throws SysException {
        String productId = ticketFinanceAddDto.getProductId();
        // 通过金融产品id查询金融产品的各类利率信息
        FinancialProductEntity financialProductEntity = baseDataFeign.financialProductById(productId);
        if (null == financialProductEntity) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_FEIGN_GET_PRODUCT_DATA_ERROR);
        }
        //设置金融产品信息  暂时注释掉 todo
//        entity.setIsAnnualizedInterestRate(financialProductEntity.getIsAnnualizedInterestRate());
//        Double interest = this.calculateFinanceInterest(ticketFinanceAddDto.getSellAmount(), financialProductEntity.getAnnualizedInterestRate());
//        entity.setEstimatedFinancingInterest(interest);
//        Double serviceChage = this.calculateServiceChage(ticketFinanceAddDto.getSellAmount(), financialProductEntity.getPlatServiceRate());
//        entity.setServiceChage(serviceChage);
//        entity.setAnnualizedInterestRate(financialProductEntity.getAnnualizedInterestRate());
//        entity.setPlatServiceRate(financialProductEntity.getPlatServiceRate());
//        entity.setIsAnnualizedPlatServiceRate(financialProductEntity.getIsAnnualizedPlatServiceRate());
//        entity.setIsGraceCost(financialProductEntity.getIsGraceCost());
//        entity.setGraceDays(financialProductEntity.getGraceDays());
//        entity.setBusinessMode(financialProductEntity.getBusinessMode());
//        entity.setSealType(financialProductEntity.getSealType());
    }

    /**
     * 计算融资利息 todo gull 计算公式待定
     *
     * @param sellAmount             融资本金
     * @param annualizedInterestRate 利率
     */
    private Double calculateFinanceInterest(Double sellAmount, Double annualizedInterestRate) {
        return sellAmount * annualizedInterestRate;
    }

    /**
     * 通过id创建参数Map
     * id为空时返回空Map，否则按照id查询
     *
     * @param id 票据id
     * @return 票据对象转化成Map
     * @throws SysException 当通过票据id查询不到票据是抛出异常
     */
    @SuppressWarnings({"unchecked"})
    private Map<String, Object> createTicketMap(String id) throws SysException {
        if (null == id) {
            return new HashMap<>(0);
        }
        TicketEntity entity = ticketService.getById(id);
        if (entity == null) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_ERROR);
        }
        return (Map<String, Object>) JSON.toJSON(entity);
    }

    /**
     * 获取融资列表统计数据
     *
     * @param user 登录用户
     * @return 融资列表统计数据
     * @throws SysException 业务异常
     */
    @Override
    @SuppressWarnings("all")
    public TicketFinanceDataDto financeData(User user) throws SysException {
        TicketFinanceDataDto result = new TicketFinanceDataDto();
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("DATE_FORMAT(create_time, '%Y-%m-%d')", "DATE_FORMAT(" + new Date() + ", '% Y-%m-%d')")
                .eq("enterprise_id", user.getEnterpriseId());
        List<TicketFinanceEntity> list = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            result.setCountToday(0);
            result.setTicketAmountToday(0.0);
        } else {
            result.setCountToday(list.size());
            result.setTicketAmountToday(list.stream().mapToDouble(TicketFinanceEntity::getFinanceAmount).sum());
        }
        queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(TicketFinanceEntity::getTicketStatus, TicketStatusEnum.FINANCE_ING_LIST)
                .eq(TicketFinanceEntity::getEnterpriseId, user.getEnterpriseId());
        list = this.list(queryWrapper);
        if (!CollectionUtils.isEmpty(list)) {
            result.setTicketAmountApproving(list.stream().mapToDouble(TicketFinanceEntity::getFinanceAmount).sum());
        } else {
            result.setTicketAmountApproving(0.0);
        }
        return result;
    }

    /**
     * 根据主键查询融资详情
     *
     * @param id   主键
     * @param user 用户
     * @return 融资详情
     * @throws SysException 异常
     */
    @Override
    public TicketFinanceDto getFinanceDetailById(String id, User user) throws SysException {
        TicketFinanceEntity entity = this.getById(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_ERROR);
        }
        TicketFinanceDto ticketFinanceDto = new TicketFinanceDto();
        BeanUtils.copyProperties(entity, ticketFinanceDto);
        // 设置处理状态
        ticketFinanceHandService.setFinanceOneTicketHandleSituation(ticketFinanceDto);
        // 找到融资相关附件信息
        List<TicketDataEntity> dataEntities = ticketDataService.getByTicketIdAndType(id, TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode());
        if (!CollectionUtils.isEmpty(dataEntities)) {
            Map<String, List<TicketDataEntity>> map = dataEntities.stream().collect(Collectors.groupingBy(TicketDataEntity::getDataType));
            ticketFinanceDto.setInvoiceList(map.get(DataTypeEnum.INVOICE.getCode()));
            ticketFinanceDto.setProofList(map.get(DataTypeEnum.TICKET.getCode()));
        }
        //签署资料
        List<BusinessContractEntity> businessContractEntities = businessContractService.getByTicketId(id, BusinessTypeEnum.TICKET_FINANCE.getCode());
        this.getContractSigner(businessContractEntities);
        ticketFinanceDto.setProtocolList(businessContractEntities);
        return ticketFinanceDto;
    }

    /**
     * 获取签署状态
     *
     * @param businessContractEntities 签署协议
     */
    @Override
    public void getContractSigner(List<BusinessContractEntity> businessContractEntities) {
        if (!CollectionUtils.isEmpty(businessContractEntities)) {
            List<String> collect = businessContractEntities.stream()
                    .map(BusinessContractEntity::getContractId)
                    .distinct().collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(collect)) {
                List<SignerEntity> contractSigner = anXinSignFeign.getContractSigner(collect);
                Map<String, SignerEntity> collect1 = contractSigner.stream()
                        .collect((Collectors.toMap(SignerEntity::getContractId, Function.identity(), (key1, key2) -> key2)));
                businessContractEntities.forEach(x -> {
                    if (null != collect1.get(x.getContractId())) {
                        x.setSignmentState(collect1.get(x.getContractId()).getSignmentState());
                    }
                });
            }
        }
    }

    /**
     * 设置签署资料
     *
     * @param ticketFinanceDto 融资协议签署
     * @return
     */
    private TicketFinanceDto getFinanceContract(TicketFinanceDto ticketFinanceDto) {
        TicketContractListDto ticketContractListDto = new TicketContractListDto();
        ticketContractListDto.setTicketId(ticketFinanceDto.getId());
        ticketContractListDto.setTicketType(ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());
        List<ContractEntity> contractEntities = contractFeign.ticketContractList(ticketContractListDto);
//        ticketFinanceDto.setProtocolList(contractEntities);
        return ticketFinanceDto;
    }

    /**
     * 凭证查询
     *
     * @param id   凭证id
     * @param user 用户
     * @return 我的凭证信息
     */
    @Override
    public MyTicketDetailDto getTicketInfoById(String id, User user) throws SysException {
        TicketEntity ticketEntity = ticketService.getById(id);
        if (ObjectUtils.isEmpty(ticketEntity)) {
            throw new SysException("未找到当前凭证信息");
        }
        MyTicketDetailDto businessDetail = new MyTicketDetailDto();
        BeanUtils.copyProperties(ticketEntity, businessDetail);
        // 文件信息  和产品确定，融资时，将母单的发票和凭证资料带过来，作为融资时的发票和凭证提交
        List<TicketDataEntity> dataList = ticketDataService.getByTicketId(ticketEntity.getParentBusinessId(), TicketActionTypeEnum.TICKET_TYPE_TICKET.getCode());
        if (!CollectionUtils.isEmpty(dataList)) {
            List<TicketDataEntity> ticketList = dataList.stream().filter(x -> x.getDataType().equals(DataTypeEnum.TICKET.getCode())).collect(Collectors.toList());
            businessDetail.setProofList(ticketList);
            List<TicketDataEntity> invoiceList = dataList.stream().filter(x -> x.getDataType().equals(DataTypeEnum.INVOICE.getCode())).collect(Collectors.toList());
            businessDetail.setInvoiceList(invoiceList);
        }
        String surplusDays = ticketCommonService.calculateSurplusDays(businessDetail.getExpireTime()
                , TicketStatusEnum.WAITING_PAYMENT.getCode());
        businessDetail.setSurplusDays(surplusDays);
        return businessDetail;
    }

    /**
     * 应收账款查询
     *
     * @param ticketId 票据id
     * @throws SysException 异常
     */
    private Double getReceivableAmout(String ticketId) throws SysException {
        if (StringUtils.isBlank(ticketId)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_RECEIVABLE_AMOUNT_NOT_FOUND);
        }
        TicketEntity ticketEntity = ticketService.getById(ticketId);
        //根据开单申请，查询应收账款数值

        if (ObjectUtils.isEmpty(ticketEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_RECEIVABLE_AMOUNT_NOT_FOUND);
        }
        return ticketEntity.getReceivableAmount();
    }

    /**
     * 融资复核列表
     *
     * @param params 筛选条件
     * @param user   用户
     * @return 融资复核列表
     */
    @Override
    public PageUtils queryReviewFinancePage(Map<String, Object> params, User user, HttpSession session) {
        IPage<TicketFinanceListDto> page = setTicketFinanceListParams(params, user);
        params.put(TICKET_STATUS, TicketStatusEnum.FINANCE_PENDING_REVIEW.getCode());
        IPage<TicketFinanceListDto> reviewFinancePage = this.baseMapper.queryReviewPage(page, params);
        List<TicketFinanceListDto> checkPageRecords = reviewFinancePage.getRecords();
        if (!CollectionUtils.isEmpty(checkPageRecords)) {
            ticketFinanceHandService.setFinanceTicketCheckOperates(checkPageRecords, session);
        }
        return new PageUtils(reviewFinancePage);
    }

    /**
     * 设置查询条件
     *
     * @param params 筛选条件
     * @param user   用户
     * @return 分页查询
     */
    private IPage<TicketFinanceListDto> setTicketFinanceListParams(Map<String, Object> params, User user) {
        if (null != user) {
            params.put("enterpriseId", user.getEnterpriseId());
        }
        //排序字段：create_time
        String pageField = (String) params.get(Constant.PAGE);
        //排序方式 order:  desc asc
        String order = (String) params.get(Constant.ORDER);
        IPage<TicketFinanceListDto> page = new Query<TicketFinanceListDto>()
                .getPage(params, StringUtils.isBlank(pageField)
                        ? StringConstant.CREATE_TIME_FILED : pageField, Constant.ASC.equals(order));
        ticketCommonService.changeTenThousand2Number(params, "startAmount");
        ticketCommonService.changeTenThousand2Number(params, "endAmount");
        return page;
    }

    /**
     * 融资复核详情
     *
     * @param id   融资id
     * @param user yoghurt
     * @return 融资详情
     * @throws SysException 异常
     */
    @Override
    public TicketFinanceReviewDto reviewInfo(String id, User user) throws SysException {
        TicketFinanceEntity entity = this.getById(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_ERROR);
        }
        TicketFinanceReviewDto ticketFinanceDto = new TicketFinanceReviewDto();
        BeanUtils.copyProperties(entity, ticketFinanceDto);
        //产品确认，融资天数是提交时间和兑付时间之前的差，固定写死

        //设置母单信息
        TicketEntity ticketEntity = ticketService.getById(entity.getTicketId());
        if (!ObjectUtils.isEmpty(ticketEntity)) {
            TicketEntity parentTicketEntity = ticketService.getById(ticketEntity.getParentId());
            if (!ObjectUtils.isEmpty(parentTicketEntity)) {
                ticketFinanceDto.setParentTicketAmount(parentTicketEntity.getTicketAllAmount());
                ticketFinanceDto.setParentTicketNo(parentTicketEntity.getTicketNo());
                ticketFinanceDto.setReceivableAmount(parentTicketEntity.getTicketAllAmount());
            }
        }
        // 找到融资相关附件信息
        List<TicketDataEntity> dataEntities = ticketDataService.getByTicketIdAndType(id, TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode());
        if (!CollectionUtils.isEmpty(dataEntities)) {
            Map<String, List<TicketDataEntity>> map = dataEntities.stream().collect(Collectors.groupingBy(TicketDataEntity::getDataType));
            ticketFinanceDto.setInvoiceList(map.get(DataTypeEnum.INVOICE.getCode()));
            ticketFinanceDto.setProofList(map.get(DataTypeEnum.TICKET.getCode()));
        }
        //设置签署合同信息
        this.setFinanceProtocolDetail(ticketFinanceDto);
        return ticketFinanceDto;
    }

    /**
     * 设置签署合同信息
     *
     * @param ticketFinanceDto 融资信息
     */
    private void setFinanceProtocolDetail(TicketFinanceReviewDto ticketFinanceDto) {
        TicketContractListDto ticketContractListDto = new TicketContractListDto();
        ticketContractListDto.setTicketId(ticketFinanceDto.getId());
        ticketContractListDto.setTicketType(ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());
        List<ContractEntity> contractEntities = contractFeign.ticketContractList(ticketContractListDto);
        if (!CollectionUtils.isEmpty(contractEntities)) {
            List<TicketContractDto> ticketContractDtos = QmBeanUtils.copyListProperties(contractEntities, TicketContractDto::new);
            //todo gull 此处需要添加按钮权限
            ticketContractDtos.stream().forEach(x -> {
                List<KeyValue> operateButton = new ArrayList<>();
                operateButton.add(new KeyValue(1, "签署"));
                x.setOperateButton(operateButton);
            });
            ticketFinanceDto.setProtocolList(ticketContractDtos);
        }

    }

    /**
     * 融资复核提交
     * 1、记录申请的操作记录、凭证的操作记录
     * 2、调用流程去审核接口，并且发送消息
     *
     * @param checkSubmit 提交参数
     * @param user        用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void financeTicketCheckSubmit(ApprovalSubmitDto checkSubmit, User user) throws SysException {
        //原申请单
        TicketFinanceEntity financeEntity = this.getById(checkSubmit.getId());
        //融资信息校验
        checkFinanceEntity(checkSubmit, financeEntity);
        //复核通过时，记录日志，不通过时，日志在回调函数中记录
        if (ApproveResultStatusEnum.APPROVE_STATUS_YES.getCode().equals(checkSubmit.getApprovalResult())) {

            checkSubmit.setCcMsg(JSON.toJSONString(new MsgInfoDto(financeEntity.getId(), GotoTypeEnum.GOTO_TYPE_FINANCE.getCode().toString()
                    , mailMessageService.getFinanceMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_PASS_CC_REVIEW), "")));

            checkSubmit.setMsg(JSON.toJSONString(new MsgInfoDto(financeEntity.getId(), GotoTypeEnum.GOTO_TYPE_FINANCE.getCode().toString()
                    , mailMessageService.getFinanceMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_APPROVE), "")));
            //记录日志
            this.setTicketOprateLog(financeEntity, user, checkSubmit.getApprovalRemark());
        } else {
            checkSubmit.setCcMsg(JSON.toJSONString(new MsgInfoDto(financeEntity.getId(), GotoTypeEnum.GOTO_TYPE_FINANCE.getCode().toString()
                    , mailMessageService.getFinanceMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_FAIL_APPLICANT_REVIEW), "")));

            checkSubmit.setMsg(JSON.toJSONString(new MsgInfoDto(financeEntity.getId(), GotoTypeEnum.GOTO_TYPE_FINANCE.getCode().toString()
                    , mailMessageService.getFinanceMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_FAIL_CC_REVIEW), "")));
        }
        //2 拉起流程处理
        ticketProcessService.addTicketProcess(checkSubmit, ApproveTypeEnum.FINANCE.getCode());

    }

    /**
     * 融资审批结束，流程的回调函数
     * 1、修改流程状态
     * 2、修改票据状态
     * 2.1 通过-拉起签收流程
     * 2.2 通过-创建协议
     * 3 操作日志
     * 4、发消息通知
     *
     * @param noticeApprovalResult 审批内容
     * @param ticketProcessEntity  流程
     * @param user                 用户
     */
    @Override
    public void ticketWithdrawCallback(NoticeApprovalResult noticeApprovalResult, TicketProcessEntity ticketProcessEntity, User user) throws SysException {
        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        TicketFinanceEntity financeEntity = baseMapper.selectById(ticketProcessEntity.getTicketFinaceId());
        if (ObjectUtils.isEmpty(financeEntity)) {
            throw new SysException("未找到当前融资申请");
        }
        ticketFinanceEntity.setId(financeEntity.getId());
//        操作记录下一状态
        String nextStatus;
        //驳回
        if (APPROVE_STATUS_NO.getCode().equals(noticeApprovalResult.getApprovalResult())) {
            ticketFinanceEntity.setTicketStatus(TicketStatusEnum.REVIEW_REJECT.getCode());
            ticketFinanceEntity.setApproveStatus(ApproveStatusEnum.PARENT_ENTERPRISE_REJECT.getCode());
            ticketProcessEntity.setApproveStatus(ApproveProcessEnum.APPROVE_PROCESS_FAIL.getCode());
            nextStatus = TicketLogStatusEnum.REVIEW_REJECT.getCode();
            //回退，处理融单的票据
            this.handleFinanceTicket(financeEntity, TicketStatusEnum.REVIEW_REJECT.getCode(), user);
            //处理票据流程图
            this.cancelFinanceFlowChart(financeEntity, user);
        } else {
            //同意
            ticketFinanceEntity.setTicketStatus(FINANCE_PENDING_APPROVE.getCode());
            ticketFinanceEntity.setApproveStatus(ApproveStatusEnum.PARENT_ENTERPRISE_PASS.getCode());
            ticketProcessEntity.setApproveStatus(ApproveProcessEnum.APPROVE_PROCESS_SUCESS.getCode());
            nextStatus = TicketLogStatusEnum.FINANCE_PENDING_APPROVE.getCode();
            //处理票据状态
            this.handleFinanceTicket(financeEntity, FINANCE_PENDING_APPROVE.getCode(), user);
//            2.1 通过-拉起签收流程
            //开始转让复核流程
            MsgInfoDto msgInfoDto = mailMessageService.setTicketFinanceMsg(financeEntity, user);
            ticketProcessService.saveTicketProcess(financeEntity.getTicketAmount()
                    , financeEntity.getId(), JSON.toJSONString(msgInfoDto), ApproveTypeEnum.FINANCE, user,
                    null
                    , TicketActionTypeEnum.TICKET_TYPE_FINANCE.getCode().toString());
//            2.2 通过-创建协议
            this.setBusinessProtocol(financeEntity.getId(), ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());
        }
        //3 通过-操作日志
        ticketOperateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), financeEntity.getId()
                , TicketLogStatusEnum.OPEN_PENDING_REVIEW.getCode(), OperateLogTypeEnum.FINANCE_REVIEW.getCode(), nextStatus, user
                , noticeApprovalResult.getApprovalRemark(),
                null, null,
                financeEntity.getOpenEnterpriseId(), financeEntity.getOpenEnterpriseName(), "", "0"
                , financeEntity.getInstinctyId(), financeEntity.getInstinctyName());

        ticketFinanceEntity.setUpdaterId(user.getId());
        //1、修改流程状态
        if (!ticketProcessService.updateById(ticketProcessEntity)) {
            throw new SysException("流程修改失败");
        }
        //2、修改票据状态
        if (!this.updateById(ticketFinanceEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_CHECK_SAVE_ERROR);
        }

    }

    /**
     * 融资票据驳回
     *
     * @param ticketFinanceEntity 融资
     * @param user                用户
     * @throws SysException 异常
     */
    private void cancelFinanceFlowChart(TicketFinanceEntity ticketFinanceEntity, User user) throws SysException {
        List<String> ticketIds = new ArrayList<>();
        ticketIds.add(ticketFinanceEntity.getTicketId());
        ticketIds.add(ticketFinanceEntity.getParentTicketId());
        if (StringUtils.isNotBlank(ticketFinanceEntity.getRetentionTicketId())) {
            ticketIds.add(ticketFinanceEntity.getRetentionTicketId());
        }
        List<TicketFlowChartEntity> chartEntities = ticketFlowChartService.listByTicketIds(ticketIds);
        chartEntities.forEach(e -> {
            if (e.getTicketId().equals(ticketFinanceEntity.getParentTicketId())) {
                e.setTicketStatus(FlowChartColourEnum.BLUE.getCode());
            } else {
                e.setTicketStatus(FlowChartColourEnum.GREY.getCode());
            }
        });
        if (!ticketFlowChartService.updateBatchById(chartEntities)) {
            throw new SysException("驳回修改流转轨迹失败！");
        }
    }

    /**
     * 融资，平台审核提交：
     * 修改凭证和申请的状态，记录日志，发送消息
     *
     * @param checkSubmit 审核结果
     * @param user        登录用户
     */
    @Override
    public void financeTicketApproveSubmit(CheckSubmit checkSubmit, User user) throws SysException {

        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        //原申请单
        TicketFinanceEntity financeEntity = this.getById(checkSubmit.getId());
        //申请人和复核人的消息
        String msg = null;
        //驳回
        if (APPROVE_STATUS_NO.getCode().equals(checkSubmit.getCheckResult())) {
            ticketFinanceEntity.setTicketStatus(TicketStatusEnum.APPROVE_REJECT.getCode());
            //回退，处理融单的票据
            this.handleFinanceTicket(financeEntity, TicketStatusEnum.APPROVE_REJECT.getCode(), user);
            //      msg = TICKET_FINANCE_APPROVE_FAIL_MSG;
        } else {
            //同意
            ticketFinanceEntity.setTicketStatus(FINANCE_PENDING_SIGN.getCode());
            //处理票据状态
            this.handleFinanceTicket(financeEntity, FINANCE_PENDING_SIGN.getCode(), user);
            //           msg = TICKET_FINANCE_APPROVE_PASS_MSG;
//            签署人的消息
            //this.sendFinanceOperateMsg(financeEntity, TICKET_FINANCE_APPROVE_PASS_SINGER_MSG, MenuButtonEnum.FINANCE_SIGN_BUTTON.getCode(), user);
        }
        ticketFinanceEntity.setId(checkSubmit.getId());
        //设置审批时间和审批人
        ticketFinanceEntity.setPlatApprovalTime(new Date());
        ticketFinanceEntity.setPlatApprovalUserId(user.getId());
        ticketFinanceEntity.setUpdaterId(user.getId());
        if (!this.updateById(ticketFinanceEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_CHECK_SAVE_ERROR);
        }
        TicketEntity ticketEntity = ticketService.getById(financeEntity.getTicketId());
        if (ObjectUtils.isEmpty(ticketEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_NOT_FOUND_ERROR);
        }
        //处理融资协议
        this.setBusinessProtocol(ticketEntity.getId(), ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());

        // 融资审核操作记录提交
//        operateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticketFinanceEntity.getId(),
//                ticketFinanceEntity.getTicketStatus(),
//                ticketEntity.getInvoiceTime(),
//                ticketFinanceEntity.getExpireTime(),
//                user,
//                checkSubmit.getRemark(),
//                null,
//                null,
//                ticketFinanceEntity.getEnterpriseId(),
//                ticketFinanceEntity.getFinanceEnterpriseName(), null);
        // 审批处理后，给申请人，复核人发送消息
        this.sendFinanceOrdinaryMsg(financeEntity, msg, Arrays.asList(financeEntity.getCreatorId(), null), user);

    }

    /**
     * 根据不同的业务类型，创建电子合同
     *
     * @param id         业务id
     * @param ticketType 业务码
     * @throws SysException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setBusinessProtocol(String id, Integer ticketType) throws SysException {
        List<TemplateEntity> templateList = anXinSignFeign.getTemplateByBusinessType(ticketType);
        if (CollectionUtils.isEmpty(templateList)) {
            throw new SysException("合同模板不存在，请联系管理员设置模板！");
        }

        List<ContractAddDto> contractAddDtoList = new ArrayList<>();
        templateList.stream().forEach(x -> {
            //1、设置合同模板
            ContractAddDto contractAddDto = new ContractAddDto();
            contractAddDto.setContractName(x.getTemplateName());
            contractAddDto.setCfcaTemplateId(x.getCfcaTemplateId());
            contractAddDto.setTemplateId(x.getId());
            contractAddDto.setContractType(ContractTypeEnum.CONTRACT_TYPE_QT.getKey());
            contractAddDto.setSignName(x.getSignName());
            contractAddDto.setContractSummary(x.getContractSummary());
            contractAddDto.setIsSign(1);
            //2 设置合同填充值
            Map<String, String> fieldMap = new HashMap<>();
            String textName = x.getTextName();
            String[] split = textName.split(StringConstant.SYMBOL_SEMICOLON);
            //todo 此处因为合同模板不确定，填充的内容也不确定，暂时写死
            String[] str = {"南京金融城", "12", "6000", "1", "2", "4"};
            if (null != split && split.length > 0) {
                for (int i = 0; i < split.length; i++) {
                    fieldMap.put(split[i], str[i]);
                }
            }
            contractAddDtoList.add(contractAddDto);
        });
        //设置审批人
        this.getApproveUser(contractAddDtoList, ticketType);
        Result result = anXinSignFeign.saveContract(contractAddDtoList);
        if (null == result || ResultCode.SUCCESS.getCode() != result.getCode()) {
            throw new SysException(result.getMsg() + "，签署资料生成失败");
        }
        //保存电子合同信息
        Object data = result.getResult().get("data");
        List<ContractEntity> contractEntityList = JSON.parseArray(JSON.toJSONString(data), ContractEntity.class);
        List<BusinessContractEntity> businessContractEntities = new ArrayList<>();
        if (!CollectionUtils.isEmpty(contractEntityList)) {
            contractEntityList.forEach(x -> {
                BusinessContractEntity businessContractEntity = new BusinessContractEntity();
                businessContractEntity.setId(UuidUtils.UUID());
                businessContractEntity.setBusinessId(id);
                businessContractEntity.setBusinessType(ticketType);
                businessContractEntity.setContractId(x.getId());
                businessContractEntity.setContractNo(x.getContractNo());
                businessContractEntity.setContractName(x.getContractName());
                businessContractEntity.setContractStatus(ContractStateEnum.CONTRACT_STATUS_UNFINISHED.getCode());
                businessContractEntity.setContractSummary(x.getContractSummary());
                businessContractEntities.add(businessContractEntity);
            });
            businessContractService.saveBatch(businessContractEntities);

        }


    }

    /**
     * 融单的流程进度
     *
     * @param id 融单id
     * @return 流程进度集合
     */
    @Override
    public List<ApUserShowInfo> getFinanceProcessProgress(String id) throws SysException {
        QueryWrapper<TicketProcessEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TicketProcessEntity::getApproveType, ApproveTypeEnum.FINANCE.getCode())
                .eq(TicketProcessEntity::getTicketFinaceId, id);
        return ticketProcessService.getApUserShowInfoList(ticketProcessService.getOne(queryWrapper));
    }


    /**
     * 设置审批人
     *
     * @param contractAddDtoList 要签署的合同列表
     * @param code               业务
     */
    public void getApproveUser(List<ContractAddDto> contractAddDtoList, Integer code) throws SysException {
        if (!CollectionUtils.isEmpty(contractAddDtoList)) {
            //查询合同模板所需的签章和签章人   todo 接口待提供，先写死
//            开单
            Integer[] userId = {193, 77};
            String[] sealId = {"0e298c0885074da68b05047e85c3bd21", "479c69afbac047e286d2abf5face0803"};
            if (ContractTicketTypeEnum.TICKET_TYPE_TRANSFER.getCode().equals(code)
                    || ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode().equals(code)) {
                //转单或融单
                userId = new Integer[]{77, 76};
                sealId = new String[]{"479c69afbac047e286d2abf5face0803", "c2b2aafa75c84454829ab6b328fa314a"};
            }

            String hostAddress;
            try {
                hostAddress = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                throw new SysException("ip地址获取失败");
            }
            Integer[] finalUserId = userId;
            String[] finalSealId = sealId;
            contractAddDtoList.forEach(x -> {
                //签章人
                List<SignInfoVO> signInfoVOList = new ArrayList<>();
                String signName = x.getSignName();
                String[] signNameArray = signName.split(StringConstant.SYMBOL_SEMICOLON);
                if (!ObjectUtils.isEmpty(signNameArray)) {
                    for (int i = 0; i < signNameArray.length; i++) {
                        SignInfoVO signInfoVO = new SignInfoVO();
                        signInfoVO.setFontSize(finalUserId[i]);
                        signInfoVO.setLocation(hostAddress);
                        //项目编号由客户自行定义，授权的编号不能重复，但一个编号可对应多个合同
                        signInfoVO.setProjectCode(ProjectCodeUtils.getProjectCode(redisTemplate));
                        signInfoVO.setSignLocation(signNameArray[i]);
                        signInfoVO.setSealId(finalSealId[i]);
                        signInfoVO.setAuthorizationTime(DateUtils.dateFormat(new Date(), YYYY_MM_DD_HH_MM_SS));
                        signInfoVOList.add(signInfoVO);
                    }
                    x.setSignInfoVOList(signInfoVOList);
                }
            });
        }

    }

    @Override
    public void executeWaitingPayment(Integer day) {
        Date date = DateUtils.dateAddDaysAll(day);
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.le("cash_time", date)
                .eq("advance_payment_status", AdvancePaymentStatusEnum.CANNOT.getCode());
        List<TicketFinanceEntity> list = this.list(queryWrapper);
        if (!CollectionUtils.isEmpty(list)) {
            //处理申请单
            list.forEach(e -> {
                e.setTicketStatus(TicketStatusEnum.WAITING_PAYMENT.getCode());
            });
            this.updateBatchById(list);
            //处理票据
            List<String> parentIds = new ArrayList<>();
            List<String> ticketRetentionIds = new ArrayList<>();
            List<String> ticketIds = new ArrayList<>();
            for (TicketFinanceEntity ticketFinanceEntity : list) {
                parentIds.add(ticketFinanceEntity.getParentTicketId());
                ticketRetentionIds.add(ticketFinanceEntity.getRetentionTicketId());
                ticketIds.add(ticketFinanceEntity.getTicketId());
            }
            Collection<TicketEntity> parent = ticketService.listByIds(parentIds);
            Collection<TicketEntity> ticketRetention = ticketService.listByIds(ticketRetentionIds);
            Collection<TicketEntity> ticket = ticketService.listByIds(ticketIds);
            parent.forEach(e -> {
                e.setCashStatus(TicketCashingEnum.WAITING_FOR_PAYMENT.getCode());
                e.setTicketStatus(TicketStatusEnum.WAITING_PAYMENT.getCode());
            });
            ticketRetention.forEach(e -> {
                e.setTicketStatus(TicketStatusEnum.INVALID.getCode());
                e.setInvalidReason(InvalidReasonEnum.WAITING_PAYMENT.getValue());
            });
            ticket.forEach(e -> {
                e.setTicketStatus(TicketStatusEnum.INVALID.getCode());
                e.setInvalidReason(InvalidReasonEnum.WAITING_PAYMENT.getValue());
            });
            parent.addAll(ticketRetention);
            parent.addAll(ticket);
            ticketService.updateBatchById(parent);
        }
        /*2、更新融资票据表数据，修改成预兑付*/
        this.rollbackFinanceTicketList(list, null, null, AdvancePaymentStatusEnum.COULD);
        /*3、更新票据表数据，修改成预兑付*/
        /*预兑付时票据表统一处理*/
    }

    /**
     * 融资审核列表
     *
     * @param params  筛选条件
     * @param user    登录用户
     * @param session session内容
     * @return 融资审核列表
     */
    @Override
    public PageUtils queryApproveFinancePage(Map<String, Object> params, User user, HttpSession session) throws
            SysException {
        IPage<TicketFinanceListDto> page = setTicketFinanceListParams(params, null);
        params.put("ticketStatus", TicketStatusEnum.FINANCE_PENDING_APPROVE.getCode());
        IPage<TicketFinanceListDto> signFinancePage = this.baseMapper.queryReviewPage(page, params);
        List<TicketFinanceListDto> signPageRecords = signFinancePage.getRecords();
        if (!CollectionUtils.isEmpty(signPageRecords)) {
            ticketFinanceHandService.setFinanceTicketApproveOperates(signPageRecords, session);
        }
        return new PageUtils(signFinancePage);
    }

    /**
     * 融单审核详情
     *
     * @param id   融资申请id
     * @param user 用户
     * @return 融单审核详情
     */
    @Override
    public TicketFinanceDto getFinanceApproveDetail(String id, User user) throws SysException {
        TicketFinanceDto financeDetailById = this.getFinanceDetailById(id, user);
        //设置签署协议数据
        this.setFinanceContract(financeDetailById);
        return financeDetailById;
    }

    /**
     * 融资协议列表
     *
     * @param params 筛选条件
     * @return 协议列表
     */
    @Override
    public List<ContractTemplateDto> getFinanceContractList(Map<String, Object> params) {
        QueryWrapper<ContractTemplateEntity> queryWrapper = new QueryWrapper<>();
        if (null != params) {
            String contractName = (String) params.get("contractName");
            queryWrapper.lambda().like(StringUtils.isNotBlank(contractName), ContractTemplateEntity::getTemplateName, contractName);
        }
        List<ContractTemplateEntity> list = contractemplateService.list(queryWrapper);
        return QmBeanUtils.copyListProperties(list, ContractTemplateDto::new);
    }

    /**
     * 根据融资凭证号融单详情
     *
     * @param ticketNo 凭证编号
     * @return 融单详情
     */
    @Override
    public TicketFinanceOrderDto getFinanceByTicketNo(String ticketNo) {
        TicketFinanceOrderDto ticketFinanceOrderDto = new TicketFinanceOrderDto();
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TicketFinanceEntity::getTicketNo, ticketNo);
        TicketFinanceEntity ticketFinanceEntity = baseMapper.selectOne(queryWrapper);
        if (ticketFinanceEntity != null) {
            BeanUtils.copyProperties(ticketFinanceEntity, ticketFinanceOrderDto);
            //设置母单信息/开立票信息
            List<TicketEntity> parentTicketEntity = new ArrayList<>(ticketService.listByIds(
                    Arrays.asList(ticketFinanceEntity.getParentTicketId(), ticketFinanceEntity.getTicketOriginId())));
            parentTicketEntity.forEach(e -> {
                if (e.getId().equals(ticketFinanceEntity.getParentTicketId())) {
                    ticketFinanceOrderDto.setParentTicketNo(e.getTicketNo());
                } else {
                    ticketFinanceOrderDto.setOpenTicketNo(e.getTicketNo());
                }
            });
        }
        ticketFinanceOrderDto.setPaymentModeStr(PaymentModeEnum.getValue(ticketFinanceOrderDto.getPaymentMode()));
        return ticketFinanceOrderDto;
    }

    /**
     * 融单管理详情
     *
     * @param id   融单id
     * @param user 用户
     * @return 融单管理详情
     */
    @Override
    public TicketFinanceDetailDto financeDetail(String id, User user) throws SysException {
        TicketFinanceDetailDto ticketFinanceDetailDto = new TicketFinanceDetailDto();
        TicketFinanceEntity financeEntity = this.getById(id);
        if (ObjectUtils.isEmpty(financeEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_NOT_FOUND);
        }
        //业务数据
        BeanUtils.copyProperties(financeEntity, ticketFinanceDetailDto);
        TicketEntity ticketEntity = ticketService.getById(financeEntity.getTicketId());
        //设置凭证信息
        if (!ObjectUtils.isEmpty(ticketEntity)) {
            ticketFinanceDetailDto.setTicketTypeSource(TicketTypeSourceEnum.getValue(ticketEntity.getTicketTypeSource()));
            ticketFinanceDetailDto.setLimitDays(ticketEntity.getLimitDays() + "");
            String surplusDays = ticketCommonService.calculateSurplusDays(ticketEntity.getCashTime(), ticketEntity.getTicketStatus());
            ticketFinanceDetailDto.setSurplusCashingDays(surplusDays.substring(0, surplusDays.length() - 2));
            ticketFinanceDetailDto.setOpenTime(ticketEntity.getInvoiceTime());
        }
        return ticketFinanceDetailDto;
    }

    /**
     * 修改融资申请信息
     *
     * @param financeUpdateDto 修改内容
     * @param user             用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTicketFinanceById(TicketFinanceUpdateDto financeUpdateDto, User user) throws SysException {

        TicketFinanceEntity financeEntity = this.getById(financeUpdateDto.getId());
        if (ObjectUtils.isEmpty(financeEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_APPLICATION_NOT_FOUND);
        }
        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        BeanUtils.copyProperties(financeUpdateDto, ticketFinanceEntity);
        //融资利率修改，重新计算融资利息
        if (null != financeUpdateDto.getAnnualizedInterestRate()) {
            Double interest = this.calculateFinanceInterest(financeEntity.getFinanceAmount(), financeUpdateDto.getAnnualizedInterestRate());
            ticketFinanceEntity.setAnnualizedInterest(interest);
        }
        //融资状态修改
        if (null != financeUpdateDto.getTicketStatus() &&
                !financeEntity.getTicketStatus().equals(financeUpdateDto.getTicketStatus()) &&
                TicketStatusEnum.FINANCE_PENDING_LOAN.getCode().equals(financeUpdateDto.getTicketStatus())) {
            financeTicketLoan(financeEntity, ticketFinanceEntity, user);
        }
//        如果修改的状态不是已放款，则不允许，暂时不需要此限制
//        if (null != financeUpdateDto.getTicketStatus() &&
//                !financeEntity.getTicketStatus().equals(financeUpdateDto.getTicketStatus()) &&
//                TicketStatusEnum.FINANCE_PENDING_LOAN.getCode().equals(financeUpdateDto.getTicketStatus())) {
//
//        }
        if (!this.updateById(ticketFinanceEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_UPDATE_ERROR);
        }

    }

    /**
     * 业务状态
     *
     * @param id 融单id
     * @return 业务状态
     */
    @Override
    public List<KeyValue> financeStatus(String id) {
        List<KeyValue> list = new ArrayList<>();
        TicketFinanceEntity financeEntity = this.getById(id);
        //如果是等待放款，则显示已放款下拉状态
        if (FINANCE_PENDING_LOAN.getCode().equals(financeEntity.getTicketStatus())) {
            list.add(new KeyValue(FINANCE_SUCCESS.getCode(), "已放款"));
        }
        return list;
    }

    /**
     * 放款处理
     *
     * @param financeEntity       原始的融单信息
     * @param ticketFinanceEntity 修改的融单信息
     * @param user                用户
     * @throws SysException 异常
     */
    private void financeTicketLoan(TicketFinanceEntity financeEntity, TicketFinanceEntity ticketFinanceEntity, User
            user) throws SysException {
        if (!ticketFinanceEntity.getTicketStatus().equals(TicketStatusEnum.FINANCE_PENDING_LOAN.getCode())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_LOAN_ERROR);
        }
        //同意
        ticketFinanceEntity.setTicketStatus(FINANCE_SUCCESS.getCode());
        //处理票据状态
        this.handleFinanceTicket(financeEntity, FINANCE_SUCCESS.getCode(), user);
        // 放款通过，给申请人、复核人发送消息
        //  this.sendFinanceOrdinaryMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_LOAN_SUCCESS_MSG, Arrays.asList(financeEntity.getCreatorId(), null), user);
        ticketFinanceEntity.setUpdaterId(user.getId());
        ticketFinanceEntity.setDisbursementDate(new Date());
//        ticketFinanceEntity.setLoanTime(new Date());
        //记录操作日志
        this.setTicketOprateLog(ticketFinanceEntity, user, null);

    }

    /**
     * 记录融资审核的操作日志
     *
     * @param ticketFinanceEntity 融资申请
     * @param user                用户
     * @param remark              备注
     * @throws SysException 异常
     */
    private void setTicketOprateLog(TicketFinanceEntity ticketFinanceEntity, User user, String remark) throws
            SysException {
        TicketEntity ticketEntity = ticketService.getById(ticketFinanceEntity.getTicketId());
        if (ObjectUtils.isEmpty(ticketEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_NOT_FOUND_ERROR);
        }
        //1 操作记录
        // 1.1 融资申请操作记录
        ticketOperateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticketFinanceEntity.getId()
                , TicketLogStatusEnum.FINANCE_PENDING_REVIEW.getCode(), OperateLogTypeEnum.REVIEW_PASS.getCode(),
                TicketLogStatusEnum.FINANCE_PENDING_APPROVE.getCode(), user
                , remark,
                null, null,
                ticketFinanceEntity.getOpenEnterpriseId(), ticketFinanceEntity.getOpenEnterpriseName(), "",
                "0", ticketFinanceEntity.getInstinctyId(), ticketFinanceEntity.getInstinctyName());
        // 1.2 融资申请操作记录
        ticketOperateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticketFinanceEntity.getId()
                , TicketLogStatusEnum.FINANCE_PENDING_REVIEW.getCode(), OperateLogTypeEnum.REVIEW_PASS.getCode(),
                TicketLogStatusEnum.FINANCE_PENDING_APPROVE.getCode(), user
                , remark,
                null, null,
                ticketFinanceEntity.getOpenEnterpriseId(), ticketFinanceEntity.getOpenEnterpriseName(), ticketFinanceEntity.getTicketId(),
                "1", ticketFinanceEntity.getInstinctyId(), ticketFinanceEntity.getInstinctyName());
        // 1.3 融资申请操作记录
        if (!StringUtils.isBlank(ticketFinanceEntity.getRetentionTicketId())) {
            ticketOperateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticketFinanceEntity.getId()
                    , TicketLogStatusEnum.FINANCE_PENDING_REVIEW.getCode(), OperateLogTypeEnum.REVIEW_PASS.getCode(),
                    TicketLogStatusEnum.FINANCE_PENDING_APPROVE.getCode(), user
                    , remark,
                    null, null,
                    ticketFinanceEntity.getOpenEnterpriseId(), ticketFinanceEntity.getOpenEnterpriseName(), ticketFinanceEntity.getRetentionTicketId(),
                    "1", ticketFinanceEntity.getInstinctyId(), ticketFinanceEntity.getInstinctyName());
        }
    }

    /**
     * 设置融资状态
     *
     * @param params 筛选条件
     */
    private void setHandStatusParams(Map<String, Object> params) {
        String handStatus = (String) params.get(StringConstant.HAND_STATUS);
        if (!StringUtils.isBlank(handStatus)) {
            List<Integer> handStatusList = TicketStatusEnum.getFinanceHandStatusList(Integer.parseInt(handStatus));
            params.put(StringConstant.HAND_STATUS_LIST, handStatusList);
        }
    }

    /**
     * 设置签署协议数据
     *
     * @param ticketFinanceDto 融资详情
     */
    private void setFinanceContract(TicketFinanceDto ticketFinanceDto) {
        TicketContractListDto ticketContractListDto = new TicketContractListDto();
        ticketContractListDto.setTicketId(ticketFinanceDto.getId());
        ticketContractListDto.setTicketType(ContractTicketTypeEnum.TICKET_TYPE_FINANCE.getCode());
        List<ContractEntity> contractEntities = contractFeign.ticketContractList(ticketContractListDto);
//        ticketFinanceDto.setProtocolList(contractEntities);
    }

    /**
     * 批量回滚融资票据
     *
     * @param ticketList        融资票据对象集合
     * @param user              登录用户
     * @param ticketApproveEnum 审核状态
     */
    @Transactional(rollbackFor = Exception.class)
    public void rollbackFinanceTicketList(List<TicketFinanceEntity> ticketList, User user, TicketStatusEnum
            ticketApproveEnum,
                                          AdvancePaymentStatusEnum advancePaymentStatus) {
        if (CollectionUtils.isEmpty(ticketList)) {
            return;
        }
        if (1 == ticketList.size()) {
            TicketFinanceEntity updateTicket = new TicketFinanceEntity();
            updateTicket.setId(ticketList.get(0).getId());
            if (ticketApproveEnum != null) {
                updateTicket.setApproveStatus(ticketApproveEnum.getCode());
            }
            if (user != null) {
                updateTicket.setUpdaterId(user.getId());
            }
            if (advancePaymentStatus != null) {
                updateTicket.setAdvancePaymentStatus(advancePaymentStatus.getCode());
            }
            this.updateById(updateTicket);
        } else {
            List<String> ticketIdList = ticketList.stream().map(TicketFinanceEntity::getTicketId).collect(Collectors.toList());
            UpdateWrapper<TicketFinanceEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("id", ticketIdList);
            if (ticketApproveEnum != null) {
                updateWrapper.set("approve_status", ticketApproveEnum.getCode());
            }
            if (user != null) {
                updateWrapper.set("updater_id", user.getId());
            }
            if (advancePaymentStatus != null) {
                updateWrapper.set("advance_payment_status", advancePaymentStatus.getCode());
            }
            this.update(updateWrapper);
        }
    }


    /**
     * 处理融单的票据状态，包括母单、融单和子单
     *
     * @param financeEntity 融单信息
     * @param code          融单状态
     */
    private void handleFinanceTicket(TicketFinanceEntity financeEntity, Integer code, User user) throws
            SysException {
        if (!ObjectUtils.isEmpty(financeEntity) && null != code) {
            List<TicketEntity> list = new ArrayList<>(3);
            //母单
            TicketEntity parentTicket = new TicketEntity();
            parentTicket.setId(financeEntity.getParentTicketId());
            parentTicket.setUpdaterId(user.getId());
            //融单
            TicketEntity ticket = new TicketEntity();
            ticket.setId(financeEntity.getTicketId());
            ticket.setUpdaterId(user.getId());
            //子单
            TicketEntity sonTicket = null;
            if (null != financeEntity.getRetentionTicketId()) {
                sonTicket = new TicketEntity();
                sonTicket.setId(financeEntity.getRetentionTicketId());
                sonTicket.setUpdaterId(user.getId());
            }
            //撤销
            if (TicketStatusEnum.CANCEL.getCode().equals(code)) {
                parentTicket.setTicketStatus(NORMAL_HOLDING.getCode());
                ticket.setTicketStatus(CANCEL.getCode());
                ticket.setInvalidReason(InvalidReasonEnum.FINANCE_TICKET_CANCEL.getValue());
                if (null != sonTicket) {
                    sonTicket.setTicketStatus(CANCEL.getCode());
                    sonTicket.setInvalidReason(InvalidReasonEnum.FINANCE_TICKET_CANCEL.getValue());
                }
                supplierCreditService.resetFinanceSupplierCredit(financeEntity, user);
            }
            //融单中
            if (TicketStatusEnum.FINANCE_ING_LIST.contains(code)) {
                ticket.setTicketStatus(code);
            }
            //融单失败
            //融资驳回，我的凭证状态全部变成已失效
            if (TicketStatusEnum.REJECT_LIST.contains(code)) {
                parentTicket.setTicketStatus(TicketStatusEnum.NORMAL_HOLDING.getCode());
                ticket.setTicketStatus(INVALID.getCode());
                ticket.setInvalidReason(InvalidReasonEnum.TICKET_FINANCE_FAIL.getValue());
                if (null != sonTicket) {
                    sonTicket.setTicketStatus(INVALID.getCode());
                    sonTicket.setInvalidReason(InvalidReasonEnum.TICKET_FINANCE_CHILD_FAIL.getValue());
                }
                supplierCreditService.resetFinanceSupplierCredit(financeEntity, user);
            }
            //融单成功
            if (TicketStatusEnum.FINANCE_SUCCESS_LIST.contains(code)) {
                ticket.setTicketStatus(TicketStatusEnum.FINANCE_SUCCESS.getCode());
                if (null != sonTicket) {
                    sonTicket.setFrozenState(FrozenStatusEnum.FROZEN_STATUS_NO.getCode());
                }
                //拆转轨迹
                ticketFlowChartManager.saveFlowChartForFinance(financeEntity, user.getId());
                supplierCreditService.deductFinanceSupplierCredit(financeEntity, user);
            }
            list.add(parentTicket);
            list.add(ticket);
            if (null != sonTicket) {
                list.add(sonTicket);
            }
            if (!ticketService.saveOrUpdateBatch(list)) {
                throw SysExceptionFactory.createSysException(TICKET_FINANCE_HANDEL_ERROR);
            }
        }
    }

    /**
     * 融资签署列表
     *
     * @param params 筛选条件
     * @param user   用户
     * @return 融资签署列表
     */
    @Override
    public PageUtils querySignFinancePage(Map<String, Object> params, User user, HttpSession session) {
        IPage<TicketFinanceListDto> page = setTicketFinanceListParams(params, user);
        params.put("ticketStatus", TicketStatusEnum.FINANCE_PENDING_SIGN.getCode());
        IPage<TicketFinanceListDto> signFinancePage = this.baseMapper.queryReviewPage(page, params);
        List<TicketFinanceListDto> signPageRecords = signFinancePage.getRecords();
        if (!CollectionUtils.isEmpty(signPageRecords)) {
            ticketFinanceHandService.setFinanceTicketSignOperates(signPageRecords, session);
        }
        return new PageUtils(signFinancePage);
    }

    /**
     * 融资签署提交
     * 1、校验签署材料是否签署
     * 2、提交：改变凭证表三条数据的状态，融单申请状态
     *
     * @param user 用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void financeTicketSignSubmit(String id, User user) throws SysException {
        TicketFinanceEntity financeEntity = this.getById(id);
        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        //校验 todo gull 待cfca数据确定之后进行对接签名验证
        if (!financeEntity.getTicketStatus().equals(TicketStatusEnum.FINANCE_PENDING_SIGN.getCode())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_SIGN_ERROR);
        }
        //修改申请单
        ticketFinanceEntity.setTicketStatus(TicketStatusEnum.FINANCE_PENDING_LOAN.getCode());
        ticketFinanceEntity.setUpdaterId(user.getId());
        ticketFinanceEntity.setId(financeEntity.getId());
        ticketFinanceEntity.setSignTime(new Date());
        if (!this.updateById(ticketFinanceEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_CHECK_SAVE_ERROR);
        }
        //处理融单的票据状态
        this.handleFinanceTicket(financeEntity, TicketStatusEnum.FINANCE_PENDING_LOAN.getCode(), user);
        TicketEntity ticket = ticketService.getById(financeEntity.getTicketId());
        if (ObjectUtils.isEmpty(ticket)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_NOT_FOUND);
        }
        // 融资签署操作记录提交
//        operateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticket.getId(),
//                ticket.getTicketStatus(),
//                ticket.getInvoiceTime(),
//                ticket.getExpireTime(),
//                user,
//                null,
//                null,
//                null,
//                ticketFinanceEntity.getEnterpriseId(),
//                ticketFinanceEntity.getFinanceEnterpriseName(), null);
        //签完协议	申请人、复核人
        //     this.sendFinanceOrdinaryMsg(financeEntity, MailMessageConstant.TICKET_FINANCE_SIGN_AGREEMENT_PASS_MSG, Arrays.asList(financeEntity.getCreatorId(), null), user);

    }


    /**
     * 融资撤销
     *
     * @param id   融单申请id
     * @param user 用户
     */
    @Override
    public void financeTicketCancel(String id, User user) throws SysException {
        TicketFinanceEntity financeEntity = this.getById(id);
        if (ObjectUtils.isEmpty(financeEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_BY_ID_ERROR);
        }
        //处理我的凭证
        this.handleFinanceTicket(financeEntity, TicketStatusEnum.CANCEL.getCode(), user);
        //处理融单申请
        TicketFinanceEntity ticketFinanceEntity = new TicketFinanceEntity();
        ticketFinanceEntity.setId(financeEntity.getId());
        ticketFinanceEntity.setTicketStatus(TicketStatusEnum.CANCEL.getCode());
        if (!this.updateById(ticketFinanceEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_PROCESS_CANCLE);
        }
        TicketEntity ticket = ticketService.getById(financeEntity.getTicketId());
        //todo 操作日志
//        operateLogService.saveTicketLog(LogActionTypeEnum.TICKET_TYPE_FINANCE.getCode(), ticket.getId(),
//                ticket.getTicketStatus(),
//                ticket.getInvoiceTime(),
//                ticket.getExpireTime(),
//                user,
//                null,
//                null,
//                null,
//                ticketFinanceEntity.getEnterpriseId(),
//                ticketFinanceEntity.getFinanceEnterpriseName(), null);
    }

    @Override
    public TicketFinanceEntity getByRetentionId(String id) {
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("retention_ticket_id", id);
        queryWrapper.eq("ticket_status", TicketStatusEnum.FINANCE_SUCCESS.getCode());
        return this.getOne(queryWrapper);
    }

    @Override
    public TicketFinanceEntity getByParentId(String id) {
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_ticket_id", id);
        queryWrapper.orderByDesc("create_time").last("limit 0,1");
        return this.getOne(queryWrapper);
    }

    @Override
    public TicketFinanceEntity getByTicketRetentionId(String id) {
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("retention_ticket_id", id);
        queryWrapper.orderByDesc("create_time").last("limit 0,1");
        return this.getOne(queryWrapper);
    }

    @Override
    public TicketFinanceEntity getByTicketId(String id) {
        QueryWrapper<TicketFinanceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ticket_id", id);
        queryWrapper.orderByDesc("create_time").last("limit 0,1");
        return this.getOne(queryWrapper);
    }


    /**
     * 融资信息校验
     *
     * @param checkSubmit 审核信息
     * @return 融资实体
     * @throws SysException 异常
     */
    private void checkFinanceEntity(ApprovalSubmitDto checkSubmit,
                                    TicketFinanceEntity financeEntity) throws SysException {
        if (APPROVE_STATUS_NO.getCode().equals(checkSubmit.getApprovalResult()) && ObjectUtils.isEmpty(checkSubmit.getApprovalResult())) {
            throw new SysException("审批驳回时，备注不能为空");
        }
        //校验
        if (ObjectUtils.isEmpty(financeEntity)) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_NO_TICKET_FOUND_BY_ID_ERROR);
        }
        if (!financeEntity.getTicketStatus().equals(TicketStatusEnum.FINANCE_PENDING_REVIEW.getCode())) {
            throw SysExceptionFactory.createSysException(TICKET_FINANCE_TICKET_CHECK_ERROR);
        }
        // 验证协议的签署状态
//        QueryWrapper<BusinessContractEntity> businessContractEntityQueryWrapper = new QueryWrapper<>();
//        businessContractEntityQueryWrapper.lambda()
//                .eq(BusinessContractEntity::getBusinessType, BusinessTypeEnum.TICKET_FINANCE.getCode())
//                .eq(BusinessContractEntity::getBusinessId, checkSubmit.getId())
//                .ne(BusinessContractEntity::getContractStatus, ContractStateEnum.CONTRACT_STATUS_FINISHED.getCode());
//        List<BusinessContractEntity> list = businessContractService.list(businessContractEntityQueryWrapper);
//        if (!CollectionUtils.isEmpty(list)) {
//            throw new SysException("请先完成协议签署后，再复核");
//        }
    }


}